package com.heima.collect.hashMap;

import java.lang.reflect.Field;
import java.util.HashMap;

/**
 *  HashMap源码必会：
 *      核心成员：
 *          loadFactor : 加载因子属性                          0.75   -- 泊松分布
 *          threshold :  扩容阈值                              12
 *          Node<K,V>[] table: 底层用来存储数据的数组          16
 *            resize(): 数组扩容方法
 *            treeifyBin() --> replacementTreeNode()  : 将链表进行树化方法
 *            untreeify() --> replacementNode(): 将红黑树转换为链表
 *
 *      1. HashMap初始化
 *          * 给loadFactor加载因子属性赋值为0.75
 *
 *      2. HashMap添加元素过程
 *          1. 计算要添加的key的哈希值
 *          2. 根据哈希值计算元素在数组中的应存入索引位置： (n - 1) & hash
 *          3. 判断该索引位置是否为null: 是则直接存入
 *          4. 不为null： 比较双方哈希值：哈希值不同，jdk8开始采用尾插法，挂载链表
 *          5. 哈希值相同，触发equals比较：equals返回false:挂载链表
 *          6. equals返回true:键相同，值覆盖!
 *
 *      3. HashMap扩容机制
 *          1. 第一次添加元素时，底层源码会将table数组由null扩容为长度16的node数组;
 *          2. 后续扩容时机：
 *              a. 当存入的元素个数 > 扩容阈值threshold
 *              b. 当链表节点个数 > 8 并且数组长度 < 64
 *
 *          3. 链表什么时候转红黑树：
 *              数组长度 >= 64 && 当链表节点个数 > 8
 *          4. 红黑树什么时候转链表：
 *              1. 当resize()扩容数组时，元素重新计算索引位置导致树的节点个数 <= 6，就会导致树退化为链表
 *              2. 当remove()删除元素，如果删的是红黑树中的节点，那么底层会判断：
 *                  如果此时红黑树的根节点为null 或者根节点的右子节点为null
 *                  或者根节点的左子节点为null 或者根节点的左孙子节点为null
 *                  四个条件任意满足一个都会导致树退化为链表
 *
 */
public class HashMapDemo {
    public static void main(String[] args) {
        HashMap<Student, String> map = new HashMap<>();
        map.put(new Student(),"value1");

        int tableLength = getMapTableLength(map);
        System.out.println("tableLength = " + tableLength);

        for (int i = 1; i <=10 ; i++) {
            map.put(new Student(),i+"");
        }
        int tableLength1 = getMapTableLength(map);
        System.out.println("tableLength1 = " + tableLength1);

    }


    private static int getMapTableLength(HashMap<Student, String> map) {
        try {
            Class clazz = map.getClass();
            Field tableField = clazz.getDeclaredField("table");
            tableField.setAccessible(true);
            Object[] tableArray = (Object[]) tableField.get(map);
            return tableArray.length;
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }


    /*

            15的二进制：
                    00000000 00000000 00000000 00001111
            &
            -1的二进制：
                    10000000 00000000 00000000 00000001
          ----------------------------------------------
                    00000000 00000000 00000000 00000001

     */
}
